package com.universest.swordholder.ui.widget

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.pow

/**
 * 可拖拽的滚动手柄组件
 *
 * 这是一个自定义的滚动指示器，在用户滚动时显示一条竖线和可拖拽的圆球，
 * 用户可以通过拖拽圆球来快速滚动内容，支持自动淡入淡出效果。
 *
 * @param modifier 修饰符
 * @param onValueChange 当滚动值变化时的回调函数，参数为当前滚动位置
 * @param lineColor 竖线的颜色
 * @param ballColor 圆球的颜色
 * @param ballTriangleColor 圆球内三角形的颜色
 * @param lineWidth 竖线的宽度
 * @param ballRadius 圆球的半径
 * @param fadeTime 自动隐藏的延迟时间（毫秒）
 * @param scrollState 滚动状态，用于获取当前滚动位置和最大值
 */
@Composable
fun DraggableScrollHandle(
    modifier: Modifier = Modifier,
    onValueChange: ((Int) -> Unit)? = null,
    lineColor: Color = Color.Gray,
    ballColor: Color = Color.Gray,
    ballTriangleColor: Color = Color.Black,
    lineWidth: Dp = 4.dp,
    ballRadius: Dp = 20.dp,
    fadeTime: Long = 1200,
    scrollState: ScrollState,
) {
    // 创建协程作用域，用于处理滚动动画
    val scope = rememberCoroutineScope()

    // 根据滚动状态计算当前位置比例（0f - 1f）
    val position by remember(scrollState.maxValue, scrollState.value) {
        derivedStateOf {
            when {
                scrollState.maxValue <= 0 -> 0f  // 如果没有可滚动内容，位置为0
                else -> (scrollState.value.toFloat() / scrollState.maxValue).coerceIn(0f, 1f)
            }
        }
    }

    // 控制组件可见性的状态
    var visible by remember { mutableStateOf(false) }
    // 跟踪当前是否正在拖拽
    var isDragging by remember { mutableStateOf(false) }

    // 根据滚动状态和拖拽状态自动控制显示/隐藏
    LaunchedEffect(scrollState.isScrollInProgress, scrollState.maxValue, isDragging) {
        // 决定是否应该显示：正在拖拽或正在滚动且有内容可滚动
        var shouldVisible = isDragging || (scrollState.isScrollInProgress && scrollState.maxValue > 0)
        if(!shouldVisible){
            // 如果不应该显示，延迟一段时间后隐藏（实现淡出效果）
            delay(fadeTime)
        }
        visible = shouldVisible
    }

    // 带有淡入淡出动画的可见性容器
    AnimatedVisibility(
        modifier = modifier,
        visible = visible,
        enter = fadeIn(),  // 淡入动画
        exit = fadeOut()   // 淡出动画
    ) {
        // 实际的可拖拽圆球和线条组件
        DraggableBallOnLine(
            modifier = Modifier.fillMaxSize(),
            lineColor = lineColor,
            ballColor = ballColor,
            ballTriangleColor = ballTriangleColor,
            lineWidth = lineWidth,
            ballRadius = ballRadius,
            position = position,  // 传入当前滚动位置比例
            onDragStatusChange = {
                isDragging = it  // 更新拖拽状态
            },
            onValueChange = { newPosition ->
                // 当用户拖拽圆球时，计算新的滚动位置
                val clampedPosition = newPosition.coerceIn(0f, 1f)
                val newValue = (scrollState.maxValue * clampedPosition).toInt()
                scope.launch {
                    // 执行滚动并回调
                    scrollState.scrollTo(newValue)
                    onValueChange?.invoke(newValue)
                }
            }
        )
    }
}

/**
 * 在竖线上的可拖拽圆球组件
 *
 * 这个组件绘制一条竖线和可以在上面拖拽的圆球，圆球内包含两个指示方向的三角形。
 *
 * @param modifier 修饰符
 * @param onValueChange 当圆球位置变化时的回调，参数为新的位置比例（0f-1f）
 * @param onDragStatusChange 当拖拽状态变化时的回调
 * @param lineColor 竖线的颜色
 * @param ballColor 圆球的颜色
 * @param ballTriangleColor 圆球内三角形的颜色
 * @param lineWidth 竖线的宽度
 * @param ballRadius 圆球的半径
 * @param position 圆球的初始位置比例（0f-1f）
 */
@Composable
fun DraggableBallOnLine(
    modifier: Modifier = Modifier,
    onValueChange: (Float) -> Unit = {},
    onDragStatusChange: (Boolean) -> Unit = {},
    lineColor: Color = Color.Gray,
    ballColor: Color = Color.Blue,
    ballTriangleColor: Color = Color.Black,
    lineWidth: Dp = 4.dp,
    ballRadius: Dp = 20.dp,
    position: Float = 0.5f,
) {
    // 圆球的当前位置状态
    var ballPosition by remember{ mutableFloatStateOf(position) }

    // 当外部传入的position变化时，同步更新ballPosition
    LaunchedEffect(position) {
        ballPosition = position
    }

    Box(
        modifier = modifier,
        contentAlignment = Alignment.Center
    ) {
        // 标记当前是否处于有效的拖拽状态（即用户确实点击在了圆球上）
        var validDrag by remember { mutableStateOf(false) }

        // 使用Canvas绘制线条和圆球，并处理拖拽手势
        Canvas(
            modifier = Modifier
                .fillMaxSize()
                .pointerInput(Unit) {
                    detectDragGestures(
                        onDragStart = { offset ->
                            // 判断用户是否点击在了圆球范围内
                            val ballRadiusPx = ballRadius.toPx()
                            // 计算圆球中心点位置
                            val centerY = (size.height - ballRadiusPx * 2) * ballPosition + ballRadiusPx
                            val centerX = size.width / 2f
                            // 计算触摸点与圆球中心的距离
                            val touchOffset = Offset(offset.x - centerX, offset.y - centerY)
                            val distanceSquared = touchOffset.getDistanceSquared()
                            // 使用1.5倍半径作为有效点击区域，增加用户体验
                            val ballRadiusSquared = (ballRadiusPx * 1.5f).pow(2)
                            validDrag = distanceSquared <= ballRadiusSquared
                            onDragStatusChange(validDrag)
                        },
                        onDrag = { change, dragAmount ->
                            change.consume()  // 消费拖拽事件
                            if(validDrag) {
                                // 根据垂直拖拽距离更新圆球位置
                                ballPosition = (ballPosition + dragAmount.y / size.height)
                                    .coerceIn(0f, 1f)  // 限制在0-1范围内
                                onValueChange(ballPosition)
                            }
                        },
                        onDragCancel =  {
                            // 拖拽被取消时重置状态
                            validDrag = false
                            onDragStatusChange(false)
                        },
                        onDragEnd = {
                            // 拖拽结束时重置状态
                            validDrag = false
                            onDragStatusChange(false)
                        }
                    )
                }
        ) {
            val canvasWidth = size.width
            val canvasHeight = size.height
            val centerX = canvasWidth / 2f
            val lineTop = 0f
            val lineBottom = canvasHeight
            val radiusPx = ballRadius.toPx()

            // 绘制竖线（在圆球上下留出空间）
            drawLine(
                color = lineColor,
                start = Offset(centerX, lineTop + radiusPx),
                end = Offset(centerX, lineBottom - radiusPx),
                strokeWidth = lineWidth.toPx()
            )

            // 计算圆球在竖线上的位置
            val ballY = lineTop + radiusPx + (lineBottom - lineTop - 2 * radiusPx) * ballPosition
            val ballCenter = Offset(centerX, ballY)

            // 绘制圆球
            drawCircle(
                color = ballColor,
                center = ballCenter,
                radius = radiusPx
            )

            // 绘制两个对称的小等腰三角形作为方向指示器
            val triangleSideLength = radiusPx * 0.4f  // 三角形边长
            val triangleHeight = triangleSideLength / 2 * 1.732f  // 等边三角形高度（√3/2 * 边长）
            val distanceToHorizontalLine = radiusPx * 0.2f  // 三角形与水平线的距离

            // 绘制朝上的三角形（位于圆球中部偏上位置）
            drawPath(
                path = androidx.compose.ui.graphics.Path().apply {
                    moveTo(ballCenter.x, ballCenter.y - triangleHeight - distanceToHorizontalLine)  // 顶点
                    lineTo(ballCenter.x - triangleSideLength / 2f, ballCenter.y - distanceToHorizontalLine) // 左下角
                    lineTo(ballCenter.x + triangleSideLength / 2f, ballCenter.y - distanceToHorizontalLine) // 右下角
                    close()  // 闭合路径形成三角形
                },
                color = ballTriangleColor
            )

            // 绘制朝下的三角形（位于圆球中部偏下位置）
            drawPath(
                path = androidx.compose.ui.graphics.Path().apply {
                    moveTo(ballCenter.x, ballCenter.y + triangleHeight + distanceToHorizontalLine)  // 底点
                    lineTo(ballCenter.x - triangleSideLength / 2f, ballCenter.y + distanceToHorizontalLine) // 左上角
                    lineTo(ballCenter.x + triangleSideLength / 2f, ballCenter.y + distanceToHorizontalLine) // 右上角
                    close()  // 闭合路径形成三角形
                },
                color = ballTriangleColor
            )
        }
    }
}

/**
 * 预览函数 - 用于Android Studio的Compose预览
 */
@Composable
@Preview
fun DraggableBallExample() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(32.dp)
    ) {
        DraggableBallOnLine(
            modifier = Modifier.fillMaxSize(),
            lineColor = Color.Gray,
            ballColor = Color(0xFF2196F3),  // Material Blue 500
            lineWidth = 6.dp,
            ballRadius = 24.dp,
            position = 0.3f  // 初始位置在30%处
        )
    }
}